package cinvestment;

import ilog.concert.IloLinearNumExpr;
import ilog.concert.IloNumVar;
import ilog.cplex.IloCplex;

import java.math.BigDecimal;
import java.util.List;

import support.AlgorithmSupport;
import util.Lang;
import util.NullOutputStream;

public class Allocation {

	private String structure = AlgorithmSupport.EXTENSIVE;
	private int N;// products number
	private int n;// plants number
	private int simulationCount; // simulation count
	private double[][] demands;
	private double variable_demand = 0.3;
	private double[] penalties;
	private double[] capacities;

	private List<Plant> plants;

	public Allocation(int N, String structure, int simulationNum,
			double[] penalties, double[] capacities, double deviation) {
		this.N = N;
		this.structure = structure;
		this.simulationCount = simulationNum;
		this.penalties = penalties;
		this.capacities = capacities;
		this.variable_demand = deviation;

		this.plants = AlgorithmSupport.createPlantsByStructure(N,
				this.structure);
		this.n = this.plants.size();
		// this.demands = AlgorithmSupport.getDemands_normal(simulationCount, N,
		// 1.0, variable_demand, 0.0, 2.0);
		this.demands = AlgorithmSupport.getDemands_uniform(simulationCount, N,
				0.0, 2.0);
	}

	public double allocate() {
		double objv = 0.0;

		BigDecimal sum = BigDecimal.ZERO;
		for (int di = 0; di < simulationCount; di++) {
			try {
				IloCplex cplex = new IloCplex();
				cplex.setOut(new NullOutputStream());
				IloNumVar[][] x = new IloNumVar[n][N];
				for (int j = 0; j < n; j++) {
					for (int i = 0; i < N; i++)
						x[j][i] = cplex.numVar(0, Double.MAX_VALUE);
				}

				IloLinearNumExpr obj = cplex.linearNumExpr();
				for (int i = 0; i < N; i++) {
					for (int j = 0; j < n; j++) {
						if (plants.get(j).isAvailable(i)) {
							obj.addTerm(-penalties[i], x[j][i]);
						}
					}
				}
				cplex.addMinimize(obj);

				for (int i = 0; i < N; i++) {
					IloLinearNumExpr left = cplex.linearNumExpr();
					for (int j = 0; j < n; j++) {
						if (plants.get(j).isAvailable(i)) {
							left.addTerm(1.0, x[j][i]);
						}
					}
					cplex.addLe(left, demands[di][i]);
				}
				for (int j = 0; j < n; j++) {
					IloLinearNumExpr left = cplex.linearNumExpr();
					for (int i = 0; i < N; i++) {
						if (plants.get(j).isAvailable(i))
							left.addTerm(1.0, x[j][i]);
					}
					cplex.addLe(left, capacities[j]);
				}

				if (di == 0)
					cplex.exportModel(Lang.projectRoot() + "\\allocat.lp");

				if (cplex.solve()) {
					sum = sum.add(BigDecimal.valueOf(cplex.getObjValue()));
				}
				cplex.end();

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		objv = sum.divide(BigDecimal.valueOf(simulationCount), 5,
				BigDecimal.ROUND_HALF_EVEN).doubleValue();
		return objv;
	}
}
